package br.com.lm.geral.util;

import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;
import java.util.Properties;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.NoSuchProviderException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import org.apache.commons.mail.Email;
import org.apache.commons.mail.EmailAttachment;
import org.apache.commons.mail.EmailException;
import org.apache.commons.mail.HtmlEmail;
import org.apache.commons.mail.MultiPartEmail;
import org.apache.commons.mail.SimpleEmail;

/**
 * @author Robson Motta
 */
public class EnviaEmail {

    public static final String PRIORITY_HIGHEST = "1";
    public static final String PRIORITY_HIGH    = "2";
    public static final String PRIORITY_NORMAL  = "3";
    public static final String PRIORITY_LOW     = "4";
    public static final String PRIORITY_LOWEST  = "5";
    
    private static final String SYSTEM_RESOURCE_BUNDLE_VAR = "msgPool";    
            
    private Transport transport;
    private String urlLogo;
    private String fromAddressDflt;
    private String fromNameDflt;
    private StringBuilder sb;
    
    private MessageProvider messageProvider;
    private String resourceBundleVar;
    
    //Construtor
    public EnviaEmail(){
        resourceBundleVar = SYSTEM_RESOURCE_BUNDLE_VAR;
        this.urlLogo = getMessageI18N("system.homeUrlLogo");
        this.fromAddressDflt = getMessageI18N("system.homeEmail");
        this.fromNameDflt = getMessageI18N("system.homeName");
        setTransport();
    }
    
    /**
     * Envia Email no formato texto
     * @param toAddress: Email do recebedor da mensagem
     * @param toName: Nome do recebedor (opcional)
     * @param fromAddress: Email do enviador da mensagem
     * @param fromName: Nome do enviador (opcional)
     * @param ccList: Lista de recebimento em cópia (opcional)
     * @param bccList: Lista de recebimento em cópia oculta (opcional)
     * @param subject: Titulo do Email
     * @param priority: Prioridade do Email (opcional)
     * @param msgsEmail: Mensagens que compoem o email
     * @throws EmailException 
     */
    public void send(String toAddress,      String toName, 
                     String fromAddress,    String fromName,
                     List<InternetAddress>  ccList,               
                     List<InternetAddress>  bccList,
                     String subject,        String priority, 
                     List<String> msgsEmail) throws EmailException {
            
        Email email = new SimpleEmail();
        email.setHostName("localhost");
        email.setSubject(subject);

        //De -> Para
        if (toName == null || toName.trim().equals(""))
            email.addTo(toAddress);
        else email.addTo(toAddress, toName);
        if (fromName == null || fromName.trim().equals(""))
            email.setFrom(fromAddress);
        else email.setFrom(fromAddress, fromName);

        //Prioridade
        if (priority != null && !priority.trim().equals("")) {
            email.addHeader("X-Priority", priority);
            if (priority.equals(PRIORITY_HIGHEST) || priority.equals(PRIORITY_HIGH)) {    
                email.addHeader("Priority", "Urgent");
                email.addHeader("Importance", "high");
            }    
        }

        //Endereço de cópia
        if (ccList != null && !ccList.isEmpty()) {
            email.setCc(bccList);
        }
            
        //Endereço de cópia oculta
        if (bccList != null && !bccList.isEmpty()) {
            email.setBcc(bccList);
        }
            
        //Conteudo Msg 
        if (sb == null)
            sb = new StringBuilder();
        else sb.setLength(0); 
        for (String mensagem: msgsEmail) {
            if (sb.length() > 0)
                sb.append("\n");
            sb.append(mensagem);                
        }
        email.setMsg(sb.toString());  
            
        //Envia mensagens...            
        try {
            if (transport == null)
                email.send();
            else {
                email.buildMimeMessage();
                Message m = email.getMimeMessage();
                transport.sendMessage(m, m.getAllRecipients());
            }    
        }    
        catch(EmailException e) { throw e; }
        catch (MessagingException me) { throw new EmailException(me); }
    }

    /**
     * Envia Email no formato texto
     * @param toAddress: Email do recebedor da mensagem
     * @param toName: Nome do recebedor (opcional)
     * @param fromAddress: Email do enviador da mensagem
     * @param fromName: Nome do enviador (opcional)
     * @param ccList: Lista de recebimento em cópia (opcional)
     * @param bccList: Lista de recebimento em cópia oculta (opcional)
     * @param subject: Titulo do Email
     * @param priority: Prioridade do Email (opcional)
     * @param msgsEmail: Mensagens que compoem o email
     * @param urlAttachments: Anexos (opcional)
     * @throws EmailException 
     */
    public void send(String toAddress,      String toName, 
                     String fromAddress,    String fromName,
                     List<InternetAddress>  ccList,               
                     List<InternetAddress>  bccList,
                     String subject,        String priority, 
                     List<String> msgsEmail, 
                     List<String> urlAttachments) throws EmailException {
    
        if (urlAttachments == null || urlAttachments.isEmpty())
            send(toAddress, toName, fromAddress, fromName, ccList, bccList,
                 subject, priority, msgsEmail);
        
        MultiPartEmail email = new MultiPartEmail();
        email.setHostName("localhost");
        email.setSubject(subject);

        //De -> Para
        if (toName == null || toName.trim().equals(""))
            email.addTo(toAddress);
        else email.addTo(toAddress, toName);
        if (fromName == null || fromName.trim().equals(""))
            email.setFrom(fromAddress);
        else email.setFrom(fromAddress, fromName);

        //Prioridade
        if (priority != null && !priority.trim().equals("")) {
            email.addHeader("X-Priority", priority);
            if (priority.equals(PRIORITY_HIGHEST) || priority.equals(PRIORITY_HIGH)) {    
                email.addHeader("Priority", "Urgent");
                email.addHeader("Importance", "high");
            }    
        }
            
        //Endereço de cópia
        if (ccList != null && !ccList.isEmpty()) {
            email.setCc(bccList);
        }
            
        //Endereço de cópia oculta
        if (bccList != null && !bccList.isEmpty()) {
            email.setBcc(bccList);
        }

        //Anexos
        for (String urlString: urlAttachments) {
            EmailAttachment attachment = new EmailAttachment();
            attachment.setDisposition(EmailAttachment.ATTACHMENT);
            String attacName = urlString.substring(urlString.lastIndexOf("/") + 1);
            attachment.setDescription(attacName);
            attachment.setName(attacName.replaceAll("[.]\\w+$",""));
            if (urlString.matches("(^(?i)(http|https)://)")) {
                //Arquivos externos
                try { attachment.setURL(new URL(urlString)); }
                catch (MalformedURLException e) {}
            }
            else {
                //Arquivos host
                attachment.setPath(urlString);
            }
            email.attach(attachment);
        }
            
        //Conteudo Msg 
        if (sb == null)
            sb = new StringBuilder();
        else sb.setLength(0); 
        for (String mensagem: msgsEmail) {
            if (sb.length() > 0)
                sb.append("\n");
            sb.append(mensagem);                
        }
        email.setMsg(sb.toString());  
            
        //Envia mensagens...            
        try {
            if (transport == null)
                email.send();
            else {
                email.buildMimeMessage();
                Message m = email.getMimeMessage();
                transport.sendMessage(m, m.getAllRecipients());
            }    
        }    
        catch(EmailException e) { throw e; }
        catch (MessagingException me) { throw new EmailException(me); }            
    }
        
    /**
     * Envia Email no formato texto
     * @param toAddress: Email do recebedor da mensagem
     * @param fromAddress: Email do enviador da mensagem
     * @param subject: Titulo do Email
     * @param msgsEmail: Mensagens que compoem o email
     * @throws EmailException 
     */
    
    public void send(String toAddress,  String toName, 
                     String subject,    List<String> msgsEmail) throws EmailException {        
        send(toAddress, toName, fromAddressDflt, fromNameDflt,
             null, null, subject, null, msgsEmail);
    }
 
    /**
     * Envia Email no formato Html
     * @param toAddress: Email do recebedor da mensagem
     * @param toName: Nome do recebedor (opcional)
     * @param fromAddress: Email do enviador da mensagem
     * @param fromName: Nome do enviador (opcional)
     * @param ccList: Lista de recebimento em cópia (opcional)
     * @param bccList: Lista de recebimento em cópia oculta (opcional)
     * @param subject: Titulo do Email
     * @param priority: Prioridade do Email (opcional)
     * @param pathImagem: Imagem a ser exibida no email, Se não informado assume o logo da empresa
     * @param msgsEmail: Mensagens que compoem o email
     * @param urlAttachments: Anexos (opcional)
     * @throws EmailException 
     */
    public void send(String toAddress,      String toName, 
                     String fromAddress,    String fromName,
                     List<InternetAddress>  ccList,               
                     List<InternetAddress>  bccList,
                     String subject,        String priority, 
                     String pathImagem,
                     List<String> msgsEmail, 
                     List<String> urlAttachments) throws EmailException {
        
        if (pathImagem == null || pathImagem.trim().equals(""))
            pathImagem = urlLogo;

        File img = new File(pathImagem);
        HtmlEmail email = new HtmlEmail();
        
        email.setHostName("localhost");
        email.setSubject(subject);

        //De -> Para
        if (toName == null || toName.trim().equals(""))
            email.addTo(toAddress);
        else email.addTo(toAddress, toName);
        if (fromName == null || fromName.trim().equals(""))
            email.setFrom(fromAddress);
        else email.setFrom(fromAddress, fromName);

        //Prioridade
        if (priority != null && !priority.trim().equals("")) {
            email.addHeader("X-Priority", priority);
            if (priority.equals(PRIORITY_HIGHEST) || priority.equals(PRIORITY_HIGH)) {    
                email.addHeader("Priority", "Urgent");
                email.addHeader("Importance", "high");
            }    
        }
            
        //Endereço de cópia
        if (ccList != null && !ccList.isEmpty()) {
            email.setCc(bccList);
        }
            
        //Endereço de cópia oculta
        if (bccList != null && !bccList.isEmpty()) {
            email.setBcc(bccList);
        }

        //Anexos
        for (String urlString: urlAttachments) {
            EmailAttachment attachment = new EmailAttachment();
            attachment.setDisposition(EmailAttachment.ATTACHMENT);
            String attacName = urlString.substring(urlString.lastIndexOf("/") + 1);
            attachment.setDescription(attacName);
            attachment.setName(attacName.replaceAll("[.]\\w+$",""));
            if (urlString.matches("(^(?i)(http|https)://)")) {
                //Arquivos externos
                try { attachment.setURL(new URL(urlString)); }
                catch (MalformedURLException e) {}
            }
            else {
                //Arquivos host
                attachment.setPath(urlString);
            }
            email.attach(attachment);
        }
            
        //Conteudo Msg 
        if (sb == null)
            sb = new StringBuilder();
        else sb.setLength(0); 
        sb.append("<html><body>");
        sb.append("<img src=cid:").append(email.embed(img)).append("/>");
        sb.append("</body></html>");        
        for (String mensagem: msgsEmail) {
            sb.append("<p>").append(mensagem).append("</p>");                 
        }
        email.setHtmlMsg(sb.toString());
        
        //Envia mensagens...            
        try {
            if (transport == null)
                email.send();
            else {
                email.buildMimeMessage();
                Message m = email.getMimeMessage();
                transport.sendMessage(m, m.getAllRecipients());
            }    
        }    
        catch(EmailException e) { throw e; }
        catch (MessagingException me) { throw new EmailException(me); }            
    }
    
    //Reuso da conexão SMTP
    private void setTransport() {
        Properties props = new Properties();
        props.setProperty("mail.transport.protocol", "smtp");
        Session mailSession = Session.getDefaultInstance(props, null);
        transport = null;
        try {
            transport = mailSession.getTransport("smtp");
            transport.connect("localhost", 25, null, null);
        }
        catch (NoSuchProviderException e) {}
        catch (MessagingException me) {}
    }

    //Informações do resource bundle
    private String getMessageI18N(String chaveMsg) {
        if (messageProvider == null  || !resourceBundleVar.equals(messageProvider.getResourceBundleVar()))
            messageProvider = new MessageProvider(resourceBundleVar);
        return messageProvider.getValueFromKey(chaveMsg);
    }
}
